package ecode

import (
	"fmt"
	"google.golang.org/grpc/codes"
	"strings"
)

// 错误类型
type ErrorType struct {
	GRPCCode codes.Code
	ErrType  string
}

// ErrorCode 错误处理的结构体
type ErrorCode struct {
	Err         error             `json:"-"`
	ErrorType   ErrorType         `json:"-"`
	CodeMessage string            `json:"error_code"`
	ErrMessage  string            `json:"error_message"`
	Detail      map[string]string `json:"detail,omitempty"`
}

// Code implement ecode.Codes interface
func (e *ErrorCode) Code() int {
	return int(e.ErrorType.GRPCCode)
}

// Message implement ecode.Codes interface
func (e *ErrorCode) Message() string {
	return e.ErrMessage
}

// Details implement ecode.Codes interface
func (e *ErrorCode) Details() []interface{} {
	details := make([]interface{}, 0, len(e.Detail))
	for k, v := range e.Detail {
		details = append(details, strings.Join([]string{k, v}, "-"))
	}
	return details
}

func (e *ErrorCode) Error() string {
	return e.ErrMessage
}

// Details implement ecode.Codes interface
func (e *ErrorCode) Append(key, val string) {
	if e.Details() == nil {
		e.Detail = make(map[string]string)
	}
	e.Detail[key] = val
}

var (
	// 系统错误
	ErrSystemError = NewError("SYSTEM_ERROR", "系统错误", ErrorType{
		GRPCCode: codes.Internal,
		ErrType:  "SystemError",
	})
	// 用户取消
	ErrCancelled = NewError("USER_CANCELLED", "用户取消请求", ErrorType{
		GRPCCode: codes.Canceled,
		ErrType:  "UserCancelled",
	})
)

// NewError 新建错误
func NewError(CodeMessage string, msg string, errType ErrorType) *ErrorCode {
	return &ErrorCode{
		ErrorType:   errType,
		CodeMessage: CodeMessage,
		ErrMessage:  msg,
	}
}

// 在已有错误码基础上，append错误描述
func BizError(code, template string, args ...interface{}) *ErrorCode {
	return &ErrorCode{
		ErrorType: ErrorType{
			GRPCCode: codes.FailedPrecondition,
			ErrType:  "BizError",
		},
		CodeMessage: code,
		ErrMessage:  fmt.Sprintf(template, args...),
	}
}

// 在已有错误码基础上，append错误描述
func Unauthenticated(message string) *ErrorCode {
	return &ErrorCode{
		ErrorType: ErrorType{
			GRPCCode: codes.Unauthenticated,
			ErrType:  "AuthenticatedError",
		},
		CodeMessage: "Unauthenticated",
		ErrMessage:  message,
	}
}

// BadRequest 新建请求错误
func BadRequest(template string, args ...interface{}) *ErrorCode {
	message := fmt.Sprintf(template, args...)
	return &ErrorCode{
		ErrorType: ErrorType{
			GRPCCode: codes.InvalidArgument,
			ErrType:  "InvalidArgument",
		},
		CodeMessage: "BAD_REQUEST",
		ErrMessage:  message,
	}
}

// 在已有错误码基础上，append错误描述
func AppendMessage(code *ErrorCode, template string, args ...interface{}) *ErrorCode {
	return &ErrorCode{
		ErrorType:   code.ErrorType,
		CodeMessage: code.CodeMessage,
		ErrMessage:  fmt.Sprintf("%s: %s", code.ErrMessage, fmt.Sprintf(template, args...)),
	}
}
